If a lock is held or acquired and then released within a method, it should be released along all execution paths.

Failing to do so could make an application deadlock-prone because there is a risk of the lock not being released.

The types tracked by the rule are: Monitor, Mutex, ReaderWriterLock, ReaderWriterLockSlim, and SpinLock from the System.Threading namespace.

This rule raises an issue when a lock is acquired in a method but only released on some paths. No issue is raised when the lock is never released in the method. The assumption is that callers will release it.

Noncompliant Code Example

class MyClass
{
  private object obj = new object();

  public void DoSomethingWithMonitor()
  {
    Monitor.Enter(obj); // Noncompliant
    if (IsInitialized())
    {
      // ...
      Monitor.Exit(obj);
    }
  }

  private ReaderWriterLockSlim lockObj = new ReaderWriterLockSlim();

  public void DoSomethingWithReaderWriteLockSlim()
  {
    lockObj.EnterReadLock(); // Noncompliant
    if (IsInitialized())
    {
      // ...
      lockObj.ExitReadLock();
    }
  }
}

Compliant Solution

class MyClass
{
  private object obj = new object();

  public void DoSomethingWithMonitor()
  {
    lock(obj) // lock() {...} is easier to use than explicit Monitor calls
    {
      if (IsInitialized())
      {
      }
    }
  }

  private ReaderWriterLockSlim lockObj = new ReaderWriterLockSlim();

  public void DoSomethingWithReaderWriteLockSlim()
  {
    lockObj.EnterReadLock();
    try
    {
      if (IsInitialized())
      {
      }
    }
    finally
    {
      lockObj.ExitReadLock();
    }
  }
}

See